#include "clientcommands.h"
#include "cmclient.h"
#include <fstream>
#include <iostream>

#define CHECK_ACCESS_DENIED {if(r == ACCES_DENIED) { cout << "Access denied." << endl; return;} }

using namespace std;

int send_msg_to_server(string s)
{
    return sendto(socket_message, s.c_str(), s.size() + 1, 0, (struct sockaddr*)&server_addr, sizeof(server_addr));
}

string getTextResponse()
{
    char buffer[2000] = {0};
    int res = recv(socket_message, buffer, 1000, 0);
    LOG << socketContainsData(socket_message) <<  " contains data " << endl;
    LOG << "Received " << res << " bytes." << endl;
    string response(buffer, res+1);
    return response;
}


string getResponse(Command &r)
{
    string response = getTextResponse();
    istringstream iss(response);
    int responseType;
    iss >> responseType;
    r = static_cast<Command>(responseType);
    return response;
}

int setTypeCommand(char* buffer, Command command)
{
    buffer[0] = (byte) command;
    return 1;
}

int appendToCommand(char* buffer, const char* msg)
{
    strcpy(buffer, msg);
    return strlen(msg) + 1;
}



void do_addFile(string filename)
{
    int fileSize = getFileSize(filename);
    if(fileSize == -1)
    {
        cerr<< "Error: cannot use " << filename << endl;
        return;
    }
    commands::AddFile c(username, fileSize, getFilenameFromPath(filename));
    send_msg_to_server(c.serialize());


    Command r;
    string response = getResponse(r);

    if(r == FILE_ALREADY_EXISTS)
    {
        cout << "Error! A file with the same name already exists in the system.\n" << endl;
        return;
    }
    if(r == BEGIN_UPLOAD)
    {
        commands::BeginUpload upload_data(response);
        sendFile(filename, servername, upload_data.port);
        cout << getFilenameFromPath(filename) << " was added." << endl;
    }


}

void do_checkout(string filename)
{
    filename = getFilenameFromPath(filename);
    commands::Checkout c(username, filename);
    send_msg_to_server(c.serialize());
    Command r;
    string response = getResponse(r);
    CHECK_ACCESS_DENIED;

    if(r == ASK_FOR_DOWNLOAD)
    {
        commands::AskForDownload cc(response);
        receiveFile(filename, cc.fileSize, server_addr);
        cout << filename << " was checked out." << endl;
    }
}

void do_undo_checkout(string filename)
{
    filename = getFilenameFromPath(filename);
    commands::genericCommand c;
    c.addType(UNDO_CHECKOUT).addString(username).addString(filename);
    send_msg_to_server(c.serialize());

    commands::genericCommand response(getTextResponse());
    Command r = response.getType();
    CHECK_ACCESS_DENIED;
    if(r == OPERATION_SUCCESS)
    {
        cout << "Checkout of file " << filename << " undone."<< endl;
    }
}




void do_checkin(string filename, string comment)
{
    filename = getFilenameFromPath(filename);
    int fileSize = getFileSize(filename);
    if(fileSize == -1)
    {
        cerr<< "Error: cannot use " << filename << endl;
        return;
    }
    commands::genericCommand c;
    c.addType(CHECKIN).addString(username).addString(filename).addString(comment).addInt(fileSize);

    string s = c.serialize();
    send_msg_to_server(s);
    Command r;
    string response = getResponse(r);
    CHECK_ACCESS_DENIED;

    if(r == BEGIN_UPLOAD)
    {
        commands::BeginUpload upload_data(response);
        sendFile(filename, servername, upload_data.port);
        cout << filename << " was checked in." << endl;
    }

    return;
}


void do_get(string filename, int version)
{
    filename = getFilenameFromPath(filename);
    commands::genericCommand c;
    c.addType(GET).addString(filename).addInt(version);
    send_msg_to_server(c.serialize());
    Command r;
    string response = getResponse(r);
    CHECK_ACCESS_DENIED;

    if(r == ASK_FOR_DOWNLOAD)
    {
        commands::AskForDownload cc(response);
        receiveFile(filename, cc.fileSize, server_addr);
        cout << filename << " was downloaded." << endl;
    }

}

void do_wiewfiles()
{
    send_msg_to_server(commands::typeOnlyCommand(VIEW_FILES));

    commands::genericCommand cc(getTextResponse());
    Command r = cc.getType();
    if(r == FILES_LIST)
    {
        int numOfFiles = cc.getInt();
        if(numOfFiles == 0)
        {
            cout << "No files in the system" << endl;
        }
        for(int i = 0; i < numOfFiles; ++i)
        {
            commands::genericCommand cc(getTextResponse());
            Command r = cc.getType();
            if(r == FILES_LIST_LINE)
            {
                cout << cc.getString() << endl;
            }
        }
    }
}

void do_viewversions(string filename)
{
    commands::genericCommand c;
    c.addType(VIEW_VERSIONS).addString(getFilenameFromPath(filename));
    send_msg_to_server(c.serialize());
    commands::genericCommand cc(getTextResponse());
    Command r = cc.getType();
    
    CHECK_ACCESS_DENIED;

    if(r == VERSIONS_LIST)
    {
        int versions = cc.getInt();

        for(int i = 0; i < versions; ++i)
        {
            commands::genericCommand cc(getTextResponse());
            Command r = cc.getType();
            int ver = cc.getInt();
            if(r == VERSIONS_LIST_LINE)
                cout << cc.getString() << endl;
        }
    }
}

void do_view_my_co()
{
    commands::genericCommand c;
    c.addType(VIEW_MY_CO).addString(username);
    send_msg_to_server(c.serialize());
    commands::genericCommand cc(getTextResponse());
    Command r = cc.getType();
	
		CHECK_ACCESS_DENIED;
		
    if(r == CO_LIST)
    {
				int numOfFiles = cc.getInt();
        if(numOfFiles == 0)
        {
            cout << "No checked out files" << endl;
        }
        for(int i = 0; i < numOfFiles; ++i)
        {
            commands::genericCommand cc(getTextResponse());
            Command r = cc.getType();
            if(r == CO_LIST_LINE)
            {
                cout << cc.getString() << endl;
            }
        }
		}
}

void do_updateowner(string op, string username_to_update, string filename)
{
    filename = getFilenameFromPath(filename);
    commands::genericCommand c;
    c.addType(UPDATE_OWNER).addString(username).addString(op).addString(username_to_update).addString(filename);
    send_msg_to_server(c.serialize());
    commands::genericCommand cc(getTextResponse());
    Command r = cc.getType();

    CHECK_ACCESS_DENIED;

    cout << username_to_update << " was " ;
    if(op == "+")
        cout << "added to";
    else
        cout << "removed from";
    cout << " " << filename << endl;

}




void handleCommand(vector<string> words, string &original)
{
    try
    {
        if(words.size() == 0)
            return;
        LOG << words.size() << " words received" << endl;
        for(unsigned int i = 0; i < words.size(); ++i)
            LOG << "\t||" << words[i] << "||" << endl;
        if(words.at(0) =="add_file")
        {
            do_addFile(words.at(1));
            return;
        }
        if(words.at(0) == "checkout")
        {
            do_checkout(words.at(1));
            return;
        }
        if(words.at(0) == "checkin")
        {
            int n = original.find(words.at(1));
            do_checkin(words.at(1), original.substr(n + words.at(1).size()));
            return;
        }
        if(words.at(0) == "get")
        {
            string filename = words.at(1);
            int version = -1;
            if(words.size() >= 3 )
            {
                stringstream ss(words.at(2));
                ss >> version;
            }
            do_get(filename, version);
            return;
        }
        if(words.at(0) == "view_files")
        {
            do_wiewfiles();
            return;
        }
        if(words.at(0) == "view_versions")
        {
            string filename = words.at(1);
            do_viewversions(filename);
            return;
        }
        if(words.at(0) == "update_owner")
        {
            string op = words.at(1);
            string username_to_update = words.at(2);
            string filename = words.at(3);
            do_updateowner(op, username_to_update, filename);
            return;
        }
        if(words.at(0) == "undo_checkout")
        {
            string filename = words.at(1);
            do_undo_checkout(filename);
            return;
        }
        if(words.at(0) == "view_my_co")
        {
						do_view_my_co();
            return;
        }
    }
    catch(...)
    {
        LOG << "bad command" << endl;
    }
    LOG << "uknown command\n";

}

#undef CASE



